home *** CD-ROM | disk | FTP | other *** search
- {$C-,I-,V-,R-,K-}
- {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
- {+ +}
- {+ PROGRAM TITLE: Cross Reference Generator +}
- {+ +}
- {+ WRITTEN BY: Peter Grogono +}
- {+ DATE WRITTEN: ? +}
- {+ +}
- {+ SUMMARY: +}
- {+ 1. Output Files: +}
- {+ a. first output file is a numbered listing +}
- {+ of the input source +}
- {+ b. second output file is cross reference +}
- {+ with each identifier followed by the +}
- {+ line numbers on which it appears. +}
- {+ 2. Listing Device: +}
- {+ The numbered source listing may optionally +}
- {+ be routed to the screen or printer (but not +}
- {+ both). +}
- {+ +}
- {+ MODIFICATION RECORD: +}
- {+ 17-APR-84 -Modified for Turbo Pascal so +}
- {+ $ includes are supported +}
- {+ +}
- {+ +}
- {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
- PROGRAM XREFG2;
- { Cross Reference Generator }
- CONST
- alfa_length = 15;
- dflt_str_len = 255;
- entrygap = 0; { # of blank lines between line numbers}
- heading : string[23] = 'Cross-Reference Listing';
- headingsize = 3; {number of lines for heading}
- LLmax = dflt_str_len;
- MaxOnLine = 8;
- Maxlines = MAXINT; {longest document permitted}
- MaxWordlen = alfa_length;{longest word read without truncation}
- Maxlinelen = 80; {length of output line}
- MaxOnPage = 60; {size of output page}
- NumKeys = 70; {number of Pascal reseve words}
- {Read your Pascal manuals on this one!}
- NumberWidth = 6;
- space : char = ' ';
- TYPE
- ALFA = string[alfa_length];
- CHARNAME = (lletter, uletter, digit, blank, quote, atab,
- EndOfLine, FileMark, otherchar );
- CHARINFO = RECORD
- name : charname;
- valu : CHAR
- END;
- COUNTER = 1..Maxlines;
- pageindex = BYTE;
- Wordindex = 1..MaxWordlen;
- Queuepointer = ^Queueitem;
- Queueitem = RECORD
- linenumber : counter;
- NextInQueue: Queuepointer
- END;
- EntryType = RECORD
- Wordvalue : alfa;
- FirstInQueue,
- lastinQueue: Queuepointer
- END;
- treepointer = ^node;
- node = RECORD
- entry : EntryType;
- left,
- right : treepointer
- END;
- GenStr = string[255];
- VAR
- bell : CHAR;
- fatal_error : BOOLEAN;
- FILE_ID, { Input file name }
- PRN_ID, { basic file name + '.PRN' }
- New_ID : string[20]; { basic file name + '.XRF' }
- form_feed : CHAR;
- Key : ARRAY[1..NumKeys] OF alfa;
- LISTING : BOOLEAN;
- tab : CHAR;
- WordTree : treepointer;
- GAP : char ;
- Currentline: INTEGER;
- FOUT: TEXT; { print output file }
- XOUT: TEXT; { xref output file }
-
-
- PROCEDURE PAGE(VAR fx: TEXT);
- BEGIN
- WRITELN(fx);
- WRITE(fx, form_feed);
- END;
-
- { FUNCTYPE: }
- { Do binary search for keyword in 'key' list. If found, return }
- { TRUE, else FALSE. }
- Function Find_in_Reserve(var kword: alfa) : boolean;
- Label Return;
- Var
- low, high, mid : integer;
- Begin
- low := 1;
- high := NUMKEYS;
- while (low <= high) do begin
- mid := (low+high) div 2;
- if kword < key[mid] then
- high := mid - 1
- else if kword > key[mid] then
- low := mid + 1
- else begin
- Find_in_Reserve := TRUE;
- goto Return;
- end;
- end;
- Find_in_Reserve := FALSE;
- Return:
- End;
-
- PROCEDURE BuildTree(VAR tree: treepointer; VAR INFILE: GenStr);
- VAR
- CurrentWord : alfa;
- FIN : TEXT; { local input file }
- currchar, { Current operative character }
- nextchar : charinfo; { Look-ahead character }
- flushing : (KNOT, DBL, STD, LIT, SCANFN, SCANFN2);
- fname : string[30];
- DoInclude : boolean; { TRUE if we discovered include file }
- fbuffer : string[255]; { Format buffer - before final Print }
- LineIn : string[255];
- LineInLast : string[255];
- cp : 0..255;
- xeof, { EOF status AFTER a read }
- xeoln : BOOLEAN; { EOLN status after a read }
-
- PROCEDURE Entertree(VAR subtree: treepointer;
- Word : alfa;
- line :counter);
- VAR
- nextitem : Queuepointer;
- BEGIN
- IF subtree=nil THEN
- BEGIN {create a new entry}
- NEW(subtree);
- WITH subtree^ DO BEGIN
- left := nil;
- right := nil;
- WITH entry DO BEGIN
- Wordvalue := Word;
- NEW(FirstInQueue);
- LastinQueue := FirstInQueue;
- WITH FirstInQueue^ DO BEGIN
- linenumber := line;
- NextInQueue := nil;
- END;{WITH FirstInQueue}
- END;{WITH entry}
- END;{WITH subtree}
- END {create a new entry}
- ELSE {append a list item}
- WITH subtree^, entry DO
- IF Word=Wordvalue THEN
- BEGIN
- IF lastinQueue^.linenumber <> line THEN
- BEGIN
- NEW(nextitem);
- WITH Nextitem^ DO BEGIN
- linenumber := line;
- NextInQueue := nil;
- END;{WITH}
- lastinQueue^.NextInQueue := Nextitem;
- lastinQueue := nextitem;
- END;
- END
- ELSE
- IF Word < Wordvalue THEN
- Entertree(left,Word,line)
- ELSE
- Entertree(right,Word,line);
- END;{Entertree}
-
- Procedure ReadC({updating} VAR nextchar : charinfo;
- {returning}VAR currchar : charinfo );
- Var
- Look : char; { Character read in from File }
- BEGIN {+++ File status module. +++
- Stores file status "AFTER" a read.
- NOTE this play on words - after one char is
- actually "PRIOR TO" the next character }
- if xeoln then begin
- LineInLast := LineIn;
- if (not EOF(FIN)) then begin
- readln(FIN, LineIn);
- cp := 0;
- xeoln := FALSE;
- end
- else
- xeof := TRUE;
- end;
- if cp >= length(LineIn) then begin
- xeoln := TRUE;
- xeof := EOF(FIN);
- Look := ' ';
- end
- else begin
- cp := cp + 1;
- Look := LineIn[cp];
- End;
- {+++ current operative character module +++}
- currchar := nextchar;
- {+++ Classify the character just read +++}
- WITH nextchar DO BEGIN{ Look-ahead character name module }
- IF xeof THEN
- name := FileMark
- ELSE IF xeoln THEN
- name := EndOfLine
- ELSE IF Look IN ['a'..'z'] THEN {lower case plus}
- name := lletter
- ELSE IF Look IN ['^','$','_','A'..'Z'] THEN {upper case}
- name := uletter
- ELSE IF Look IN ['0'..'9'] THEN {digit}
- name := digit
- ELSE IF Look = '''' THEN
- name := quote
- ELSE IF Look = TAB THEN
- name := atab
- ELSE IF Look = space THEN
- name := blank
- ELSE
- name := otherchar;
- CASE name of{ store character value module }
- EndOfLine,
- FileMark: Valu := space;
- lletter: Valu := upcase(look); { Cnvrt to uppcase }
- ELSE valu := look;
- END{ case name of };
- End{ Look-ahead character name module };
- END; {of ReadC}
-
- PROCEDURE GetL( VAR fbuffer : GenStr );
- {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
- {+ Get a line of text into users buffer. +}
- {+ Flushes comment lines: +}
- {+ Flushes lines of Literals: 'this is it' +}
- {+ Ignores special characters & tabs: +}
- {+ Recognizes End of File and End of Line. +}
- {+ +}
- {+GLOBAL +}
- {+ flushing : (KNOT, DBL, STD, LIT, SCANFN); +}
- {+ LLmax = 0..Max Line length; +}
- {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
- VAR
- state : (scanning, terminal, overflow);
- sawdot : boolean;
- BEGIN { GetL }
- fbuffer := '';
- fname := '';
- fatal_error := FALSE;
- state := scanning;
- REPEAT
- ReadC(nextchar, currchar);
- IF (length(fbuffer) >= LLmax) THEN{ exceeded length of buffer }
- BEGIN{ reset EOLN }
- fatal_error := TRUE;
- state := overflow;
- fbuffer := '';
- WRITE(bell);
- WRITELN('EXCEEDED LENGTH OF INPUT BUFFER');
- END
- ELSE
- BEGIN
- IF (currchar.name IN [FileMark,EndOfLine]) THEN
- state:=terminal{ END of line or END of file };
- CASE flushing of
- KNOT:
- CASE currchar.name of
- lletter, uletter, digit, blank:
- BEGIN{ store }
- fbuffer := concat(FBUFFER,CURRCHAR.VALU) ;
- END;
- atab, quote, otherchar:
- BEGIN{ Flush comments -convert
- tabs & other chars to spaces }
- IF (currchar.valu='(') and (nextchar.valu='*')
- THEN flushing := DBL
- ELSE IF (currchar.valu='{') THEN
- flushing := STD
- ELSE IF currchar.name=quote THEN
- flushing := LIT;
- { convert to a space }
- fbuffer := concat(fbuffer,GAP);
- END;
- ELSE { END of line -or- file mark }
- fbuffer := concat(fbuffer,currchar.valu)
- END{ case currchar name of };
- DBL: { scanning for a closing - double comment }
- IF (currchar.valu ='*') and (nextchar.valu =')')
- THEN flushing := KNOT;
- STD: begin { scanning for a closing curley }
- IF currchar.valu = '}' THEN
- flushing := KNOT;
- { Check if incl } if (currchar.valu = '$') and (nextchar.valu = 'I') then
- flushing := SCANFN;
- end;
- LIT: { scanning for a closing quote }
- IF currchar.name = quote THEN
- flushing := KNOT;
- SCANFN: if (nextchar.valu<>' ') and (nextchar.valu<>TAB) then
- begin
- flushing := SCANFN2;
- SAWDOT := FALSE;
- end;
- SCANFN2: if (currchar.valu in ['A'..'Z','0'..'9','.'])
- then begin
- fname := concat(fname, currchar.valu);
- if currchar.valu = '.' then SAWDOT := TRUE;
- end
- else begin
- if length(fname) = 0 then { Make sure we ignore $I-}
- DoInclude := FALSE { compiler directive }
- else begin
- if not SAWDOT then fname := Concat(fname, '.PAS');
- DoInclude := TRUE;
- end;
- flushing := STD;
- end;
- END{ flushing case }
- END{ ELSE }
- UNTIL (state<>scanning);
- END; {of GetL}
-
- PROCEDURE ReadWord;
- {++++++++++++++++++++++++++++++++++++++++++++++++}
- {+ +}
- {+ Analyze the Line into "words" +}
- {+ +}
- {++++++++++++++++++++++++++++++++++++++++++++++++}
- LABEL 1;
- VAR
- ix, {temp indexer}
- idlen, {length of the word}
- Cpos : BYTE; { Current Position pointer }
- BEGIN{ ReadWord }
- Cpos := 1; { start at the beginning of a line }
- WHILE Cpos < length(fbuffer) DO
- BEGIN {Cpos<length(fbuffer)}
- WHILE (Cpos < length(fbuffer)) AND (fbuffer[Cpos]=space) DO
- Cpos:=Cpos + 1; {--- skip spaces ---}
- idlen := 0;
- WHILE (Cpos < length(fbuffer)) AND (fbuffer[Cpos ] <> space) DO
- BEGIN{ accept only non-spaces }
- IF idlen < MaxWordlen THEN
- BEGIN
- idlen := idlen + 1;
- CurrentWord[idlen] := fbuffer[Cpos];
- END;
- Cpos := Cpos +1;
- END{ WHILE };
- CurrentWord[0] := chr(idlen);
- IF length(CurrentWord)=0 THEN {no word was found} GOTO 1;
-
- IF (not Find_in_Reserve(CurrentWord)) and {check if reserved word}
- (not (CurrentWord[1] in ['0'..'9'])) then {or numeric constant}
- EnterTree(tree,CurrentWord,Currentline);
-
- 1:{Here is no word <length of word=0>};
- END; {WHILE Cpos<length(fbuffer)}
- END; {of Readword}
-
- BEGIN{BuildTree}
- flushing := KNOT{ flushing };
- DoInclude := FALSE;
- xeoln := TRUE;
- xeof := FALSE;
- LineIn := '';
- ASSIGN(FIN,INFILE);
- RESET(FIN);
- IF IOresult <> 0 THEN
- BEGIN
- WRITE(BELL);
- WRITELN('File ',INFILE,' not found !!!!!!');
- fatal_error := TRUE;
- END;
- nextchar.name := blank; { Initialize next char to a space }
- nextchar.valu := space;
- ReadC({update} nextchar, { Initialize current char to space }
- {returning} currchar); { First char from file in nextchar }
- WHILE ((currchar.name<>filemark) AND (NOT fatal_error)) DO
- BEGIN
- Currentline := Currentline + 1;
- GetL(fbuffer) { attempt to read the first line };
- Writeln(Fout, Currentline:6,': ',LineInLast);
- IF listing THEN Writeln(Currentline:6,': ',LineInLast)
- else if (Currentline mod 100) = 0 then
- writeln('ON LINE : ',Currentline:0);
- ReadWord; {Analyze the Text into single 'words' }
- if DoInclude then Begin
- BuildTree(tree, fname); { recursively do include }
- DoInclude := FALSE;
- end;
- END; {While}
- close(FIN);
-
- END; {of BuildTree}{CLOSE(PRN_ID);}
-
- PROCEDURE PrintTree(tree: treepointer);
- {
- GLOBAL
- MaxOnLine = max line references per line
- NumberWidth = field for each number
- }
- VAR
- pageposition: pageindex;
- PROCEDURE PrintEntry(subtree: treepointer;
- VAR position: pageindex);
- VAR ix: Wordindex;
- itemcount : 0..Maxlinelen;
- itemptr : Queuepointer;
- PROCEDURE PrintLine(VAR Currentposition: pageindex;
- newlines: pageindex);
- VAR
- linecounter: pageindex;
- BEGIN
- IF (Currentposition + newlines) < MaxOnPage THEN
- BEGIN
- FOR linecounter:=1 TO newlines DO WRITELN(XOUT);
- Currentposition := Currentposition + newlines;
- END
- ELSE
- BEGIN
- PAGE(XOUT);
- WRITELN(XOUT,heading);
- FOR linecounter := 1 TO headingsize - 1 DO
- WRITELN(XOUT);
- Currentposition := headingsize + 1;
- END
- END;{PrintLine}
-
- BEGIN{PrintEntry}
- IF subtree<>nil THEN
- WITH subtree^ DO BEGIN
- PrintEntry(left,position);
- PrintLine(position,entrygap + 1);
- WITH entry DO BEGIN
- FOR ix := 1 to length(WordValue) do WRITE(XOUT, WordValue[ix]);
- WRITE(XOUT, space:(MaxWordLen-length(WordValue)));
- itemcount := 0;
- itemptr := FirstInQueue;
- WHILE itemptr <> nil DO
- BEGIN
- itemcount := itemcount + 1;
- IF itemcount > MaxOnLine THEN
- BEGIN
- PrintLine(position,1);
- WRITE(XOUT, space:MaxWordlen);
- itemcount := 1;
- END;
- WRITE(XOUT, itemptr^.linenumber: numberwidth);
- itemptr := itemptr^.NextInQueue;
- END;{WHILE}
- END; {WITH entry}
- PrintEntry(right,position);
- END; {WITH subtree^}
- END; {PrintEntry}
-
- BEGIN{PrintTree}
- PagePosition := MaxOnPage;
- PrintEntry(tree,PagePosition);
- END; {of PrintTree}{CLOSE(New_ID);}
-
- FUNCTION ConnectFiles: boolean;
- TYPE
- Linebuffer = string[80];
- VAR
- ix : BYTE;
- BEGIN{ ConnectFiles }
- fatal_error := FALSE;
- ConnectFiles := TRUE;
- WRITELN('Enter Complete Filenames') ;
- WRITELN ;
- WRITE('Input File: ');
- READLN(FILE_ID);
- WRITELN;
- WRITE('Printed output: ');
- READLN(PRN_ID);
- WRITELN;
- WRITE('Cross-Reference output: ');
- READLN(NEW_ID);
- WRITELN;
- Assign(fout,PRN_ID);
- Rewrite(FOUT);
- if IOresult <> 0 then begin
- writeln('Could not open ',PRN_ID,' (print output file).');
- ConnectFiles := FALSE;
- fatal_error := TRUE;
- end;
- assign(xout,NEW_ID);
- Rewrite(Xout) ;
- if IOresult <> 0 then begin
- writeln('Could not open ',NEW_ID,' (xref output file).');
- ConnectFiles := FALSE;
- fatal_error := TRUE;
- end;
- END{ of ConnectFiles };
-
- PROCEDURE Initialize;
- VAR
- Ch: CHAR;
- BEGIN
- bell := ^G; GAP := ' ' ;
- Currentline := 0;
- IF ConnectFiles THEN
- BEGIN
- Key[ 1] := 'ABSOLUTE';
- Key[ 2] := 'AND';
- Key[ 3] := 'ARRAY';
- Key[ 4] := 'ASSIGN';
- Key[ 5] := 'BEGIN';
- Key[ 6] := 'BOOLEAN';
- Key[ 7] := 'BYTE';
- Key[ 8] := 'CASE';
- Key[ 9] := 'CHAIN';
- Key[10] := 'CHAR';
- Key[11] := 'CHR';
- Key[12] := 'CLOSE';
- Key[13] := 'CONCAT';
- Key[14] := 'CONST';
- Key[15] := 'COPY';
- Key[16] := 'DELETE';
- Key[17] := 'DIV';
- Key[18] := 'DO';
- Key[19] := 'DOWNTO';
- Key[20] := 'ELSE';
- Key[21] := 'END';
- Key[22] := 'EOF';
- Key[23] := 'EOLN';
- Key[24] := 'EXECUTE';
- Key[25] := 'EXIT';
- Key[26] := 'EXTERNAL';
- Key[27] := 'FALSE';
- Key[28] := 'FILE';
- Key[29] := 'FILLCHAR';
- Key[30] := 'FOR';
- Key[31] := 'FORWARD';
- Key[32] := 'FUNCTION';
- Key[33] := 'GOTO';
- Key[34] := 'IF';
- Key[35] := 'IN';
- Key[36] := 'INLINE';
- Key[37] := 'INPUT';
- Key[38] := 'INTEGER';
- Key[39] := 'LABEL';
- Key[40] := 'LENGTH';
- Key[41] := 'MOD';
- Key[42] := 'NIL';
- Key[43] := 'NOT';
- Key[44] := 'OF';
- Key[45] := 'OR';
- Key[46] := 'ORD';
- Key[47] := 'OUTPUT';
- Key[48] := 'PACKED';
- Key[49] := 'PROCEDURE';
- Key[50] := 'PROGRAM';
- Key[51] := 'REAL';
- Key[52] := 'RECORD';
- Key[53] := 'REPEAT';
- Key[54] := 'SET';
- Key[55] := 'SHL';
- Key[56] := 'SHR';
- Key[57] := 'STRING';
- Key[58] := 'SUCC';
- Key[59] := 'TEXT';
- Key[60] := 'THEN';
- Key[61] := 'TO';
- Key[62] := 'TRUE';
- Key[63] := 'TYPE';
- Key[64] := 'UNTIL';
- Key[65] := 'VAR';
- Key[66] := 'WHILE';
- Key[67] := 'WITH';
- Key[68] := 'WRITE';
- Key[69] := 'WRITELN';
- Key[70] := 'XOR';
- tab := CHR(9); { ASCII Tab character }
- form_feed := CHR(12); gap := CHR(32);
- WRITE('List file to console (Y/N)?: ');
- READ(kbd,Ch);
- LISTING := ( (Ch='Y') OR (Ch='y') );
- WRITELN; WRITELN;
- END; {IF ConnectFiles}
- END; {of Initialize}
-
- BEGIN { Cross Reference }
- CLRSCR;
- WRITELN(' ':22, 'CROSS REFERENCE GENERATOR');
- WRITELN;WRITELN;WRITELN;WRITELN;
- Initialize;
- IF NOT fatal_error THEN
- BEGIN
- WordTree := NIL; {Make the Tree empty}
- writeln('Pass 1 [Listing] Begins ...');BuildTree(WordTree, FILE_ID);
- close(FOUT) ;
- writeln('Pass 2 [Cross-Ref] Begins ...');PrintTree(WordTree);
- close(XOUT);
- END;
- WRITELN;
- END. { Cross Reference }
-
-